/*
 * Copyright (c) 2009-2011 Ricardo Quesada
 * Copyright (c) 2011-2012 Zynga Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */


#import <Box2d/Box2D.h>
#import "cocos2d.h"
#import "SimpleAudioEngine.h"

#import "GameNode.h"
#import "GameConstants.h"
#import "EnemyCar.h"

//
// Enemycar: An car enemy that is capable of killing the hero
//
// Supported parameters:
//	motorRPM (float): The RPM of the "front" wheel.
//						Negative values means that the car moves to the left. 
//						Positives values to the right.
//

@implementation Enemycar
-(id) initWithBody:(b2Body*)body game:(GameNode*)game
{
	if( (self=[super initWithBody:body game:game]) ) {
	
		// default RPM (move to left)
		motorRPM_ = -60;
		
		CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"enemycar.png"];
		[self setDisplayFrame:frame];

		// bodyNode properties
		reportContacts_ = BN_CONTACT_NONE;
		preferredParent_ = BN_PREFERRED_PARENT_SPRITES_PNG;
		isTouchable_ = NO;

		
		//
		// Mekanimo Inegration
		//
		
		// 0: destroy already created fixtures. We are going to create new fixtures / bodies
		[self destroyAllFixturesFromBody:body];
		

		// 1: Make Mekanimo happy.
		b2World *m_world = [game world];
		
		// IMPORTANT:
		// Mekanimo exports C++ code compatible with Box2d 2.02, but LevelSVG uses Box2d v2.1
		// So, you should make the following changes in order to use the code exported by Mekanimo:
		//
		// box2d 2.02:
		//   body->CreateFixture(x);
		//
		// box2d 2.1:
		//   body->CreateFixture(x,0);
		//
		// You need to set the dynamic objects as dynamic in v2.1:
		//   body->SetType(b2_dynamicBody);

	
		
		//
		// 2: Copy & Paste the code generated by Mekanimo
		// This code was generated by enemycar.mek (See LevelSVG/Resources/Makanimo )
		//

        b2BodyDef bodyDef;
        b2Vec2 initVel;
        b2PolygonShape shape;
        b2CircleShape circleShape;
        b2FixtureDef fd;
        b2RevoluteJointDef revJointDef;
        b2DistanceJointDef jointDef;
        b2Vec2 pos;
        b2Vec2 axis;
        
        
        //Polygons
        //suspensionLeft
        bodyDef.position.Set(-0.483184f, -0.188442f);
        bodyDef.angle = 0.000000f;
        b2Body* suspensionLeft = m_world->CreateBody(&bodyDef);
        initVel.Set(0.000000f, 0.000000f);
        suspensionLeft->SetLinearVelocity(initVel);
        suspensionLeft->SetAngularVelocity(0.000000f);
        
        b2Vec2 suspensionLeft_vertices[4];
        suspensionLeft_vertices[0].Set(-0.061740f, -0.112743f);
        suspensionLeft_vertices[1].Set(0.061740f, -0.112743f);
        suspensionLeft_vertices[2].Set(0.061740f, 0.112743f);
        suspensionLeft_vertices[3].Set(-0.061740f, 0.112743f);
        shape.Set(suspensionLeft_vertices, 4);
        fd.shape = &shape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        
        suspensionLeft->CreateFixture(&fd);
        
        //suspensionRight
        bodyDef.position.Set(0.518080f, -0.196495f);
        bodyDef.angle = 0.000000f;
        b2Body* suspensionRight = m_world->CreateBody(&bodyDef);
        initVel.Set(0.000000f, 0.000000f);
        suspensionRight->SetLinearVelocity(initVel);
        suspensionRight->SetAngularVelocity(0.000000f);
        
        b2Vec2 suspensionRight_vertices[4];
        suspensionRight_vertices[0].Set(-0.069793f, -0.115427f);
        suspensionRight_vertices[1].Set(0.069793f, -0.115427f);
        suspensionRight_vertices[2].Set(0.069793f, 0.115427f);
        suspensionRight_vertices[3].Set(-0.069793f, 0.115427f);
        shape.Set(suspensionRight_vertices, 4);
        fd.shape = &shape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        
        suspensionRight->CreateFixture(&fd);
        
        
        //Circles
        //wheelLeft
        bodyDef.position.Set(-0.485868f, -0.301185f);
        bodyDef.angle = 0.000000f;
        b2Body* wheelLeft = m_world->CreateBody(&bodyDef);
        initVel.Set(0.000000f, 0.000000f);
        wheelLeft->SetLinearVelocity(initVel);
        wheelLeft->SetAngularVelocity(0.000000f);
        circleShape.m_radius = 0.250000f;
        fd.shape = &circleShape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        
        wheelLeft->CreateFixture(&fd);
        
        //wheelRight
        bodyDef.position.Set(0.507343f, -0.274341f);
        bodyDef.angle = 0.000000f;
        b2Body* wheelRight = m_world->CreateBody(&bodyDef);
        initVel.Set(0.000000f, 0.000000f);
        wheelRight->SetLinearVelocity(initVel);
        wheelRight->SetAngularVelocity(0.000000f);
        circleShape.m_radius = 0.250000f;
        fd.shape = &circleShape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        
        wheelRight->CreateFixture(&fd);
        
        //Compounds (shapes welded together)
        //Compound 0
        bodyDef.position.Set(0.007901f, 0.138810f);
        bodyDef.angle = 0.0f;
        b2Body* compound0 = m_world->CreateBody(&bodyDef);
        initVel.Set(0.0f, 0.0f);
        compound0->SetLinearVelocity(initVel);
        compound0->SetAngularVelocity(0.0f);
        //cartLeft
        b2Vec2 cartLeft_vertices[4];
        cartLeft_vertices[0].Set(-0.568931f, -0.284302f);
        cartLeft_vertices[1].Set(-0.413239f, -0.284302f);
        cartLeft_vertices[2].Set(-0.413239f, 0.005608f);
        cartLeft_vertices[3].Set(-0.568931f, 0.005608f);
        shape.Set(cartLeft_vertices, 4);
        fd.shape = &shape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        compound0->CreateFixture(&fd);
        //cartUpper
        b2Vec2 cartUpper_vertices[4];
        cartUpper_vertices[0].Set(-0.807901f, -0.144716f);
        cartUpper_vertices[1].Set(0.792099f, -0.144716f);
        cartUpper_vertices[2].Set(0.792099f, 0.193513f);
        cartUpper_vertices[3].Set(-0.807901f, 0.193513f);
        shape.Set(cartUpper_vertices, 4);
        fd.shape = &shape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        compound0->CreateFixture(&fd);
        //cartRight
        b2Vec2 cartRight_vertices[4];
        cartRight_vertices[0].Set(0.424280f, -0.300408f);
        cartRight_vertices[1].Set(0.579973f, -0.300408f);
        cartRight_vertices[2].Set(0.579973f, 0.037820f);
        cartRight_vertices[3].Set(0.424280f, 0.037820f);
        shape.Set(cartRight_vertices, 4);
        fd.shape = &shape;
        fd.density = 0.015000f;
        fd.friction = 0.300000f;
        fd.restitution = 0.600000f;
        fd.filter.groupIndex = int16(0);
        fd.filter.categoryBits = uint16(65535);
        fd.filter.maskBits = uint16(65535);
        compound0->CreateFixture(&fd);
        
        //Revolute joints
        pos.Set(-0.475131f, -0.290447f);
        revJointDef.Initialize(suspensionLeft, wheelLeft, pos);
        revJointDef.collideConnected = false;
        m_world->CreateJoint(&revJointDef);
        
        //Motors
        pos.Set(0.528818f, -0.279710f);
        revJointDef.Initialize(suspensionRight, wheelRight, pos);
        revJointDef.collideConnected = false;
        revJointDef.maxMotorTorque = 10000.000000f;
        revJointDef.motorSpeed = 160.000000f / 60;
        revJointDef.enableMotor = true;
		motor_ = (b2RevoluteJoint*)m_world->CreateJoint(&revJointDef);  // IMPORTANT: This line was modified manually
																		// to obtain a reference to the motor
		
        
        //Vertical constraints
        b2PrismaticJointDef vPrismJointDef;
        pos.Set(0.501974f, -0.107911f);
        axis.Set(0.0f, 1.0f);
        vPrismJointDef.Initialize(suspensionRight, compound0, pos, axis);
        m_world->CreateJoint(&vPrismJointDef);
        
        pos.Set(-0.491237f, -0.113280f);
        axis.Set(0.0f, 1.0f);
        vPrismJointDef.Initialize(suspensionLeft, compound0, pos, axis);
        m_world->CreateJoint(&vPrismJointDef);
		
		
		// END OF COPY & PASTE.
		
		
		// 3. Reposition the created bodies:
		wheelLeft->SetTransform( wheelLeft->GetPosition() + body->GetPosition(), wheelLeft->GetAngle() );
		wheelRight->SetTransform( wheelRight->GetPosition() + body->GetPosition(), wheelRight->GetAngle() );
		compound0->SetTransform( compound0->GetPosition() + body->GetPosition(), compound0->GetAngle() );
		suspensionRight->SetTransform( suspensionRight->GetPosition() + body->GetPosition(), suspensionRight->GetAngle() );
		suspensionLeft->SetTransform( suspensionLeft->GetPosition() + body->GetPosition(), suspensionLeft->GetAngle() );

		// 4. Set the bodies as dynamic (needed in box2d 2.1)
		wheelLeft->SetType(b2_dynamicBody);
		wheelRight->SetType(b2_dynamicBody);
		compound0->SetType(b2_dynamicBody);
		suspensionLeft->SetType(b2_dynamicBody);
		suspensionRight->SetType(b2_dynamicBody);
		
		// 5. Connect b2Body objects with BodyNode objects
		BodyNode *wheelL = [[BodyNode alloc] initWithBody:wheelLeft game:game];
		[wheelL setPreferredParent:BN_PREFERRED_PARENT_SPRITES_PNG];
		frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"wheel.png"];
		[wheelL setDisplayFrame:frame];
		[game addBodyNode:wheelL z:1];	// wheels on top of cart
		wheelLeft->SetUserData(wheelL);
		wheelLeft_ = wheelLeft;					// keep weak reference
		suspensionLeft_ = suspensionLeft;		// keep weak reference
		
		BodyNode *wheelR = [[BodyNode alloc] initWithBody:wheelRight game:game];
		[wheelR setPreferredParent:BN_PREFERRED_PARENT_SPRITES_PNG];
		[wheelR setDisplayFrame:frame];
		[game addBodyNode:wheelR z:1];	// wheels on top of cart
		wheelRight->SetUserData(wheelR);	
		wheelRight_ = wheelRight;				// keep weak reference
		suspensionRight_ = suspensionRight;		// keep weak reference


		// 6. Destroy unused b2body object and connect enemycar main b2Body object with self
		m_world->DestroyBody(body);
		[self setBody:compound0];
		compound0->SetUserData(self);
			

	}
	return self;
}

-(void) setParameters:(NSDictionary *)params
{
	[super setParameters:params];

	NSString *motorRPM = [params objectForKey:@"motorRPM"];
	
	if( motorRPM ) {
		motorRPM_ = [motorRPM floatValue];
	
	}
	
	motor_->SetMotorSpeed( -motorRPM_ / 60 );
	
}

-(void) touchedByBullet:(id)bullet
{
	[game_ removeB2Body:body_];
	
	[game_ removeB2Body:wheelLeft_];
	[game_ removeB2Body:wheelRight_];
	[game_ removeB2Body:suspensionLeft_];
	[game_ removeB2Body:suspensionRight_];
	
	wheelRight_ = wheelLeft_ = NULL;
	suspensionLeft_ = suspensionRight_ = NULL;
	
	
	[[SimpleAudioEngine sharedEngine] playEffect: @"enemy_killed.wav"];
	[game_ increaseScore:10];
}

@end